/*
 * Tranquil Java Integrated Development Environment
 *
 * The GNU General Public License Version 3
 *
 * Copyright (C) 2021 Autumn Lamonte
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @author Autumn Lamonte [AutumnWalksTheLake@gmail.com] ⚧ Trans Liberation Now
 * @version 1
 */
package tjide.ui;

import java.util.ArrayList;
import java.util.List;
import java.text.MessageFormat;
import java.util.ResourceBundle;

import gjexer.TAction;
import gjexer.TButton;
import gjexer.TCommand;
import gjexer.TList;
import gjexer.TWindow;
import gjexer.bits.CellAttributes;
import gjexer.event.TCommandEvent;
import static gjexer.TCommand.*;
import static gjexer.TKeypress.*;

import tjide.debugger.Breakpoint;
import tjide.project.FileTarget;
import tjide.project.Project;
import tjide.project.Target;

/**
 * BreakpointsWindow is a permanent window that shows a list of breakpoints.
 */
public class BreakpointsWindow extends TWindow {

    /**
     * Translated strings.
     */
    private static ResourceBundle i18n = ResourceBundle.getBundle(BreakpointsWindow.class.getName());

    // ------------------------------------------------------------------------
    // Constants --------------------------------------------------------------
    // ------------------------------------------------------------------------

    private static final TCommand cmEditBreakpoint      = new TCommand(1020);
    private static final TCommand cmDeleteBreakpoint    = new TCommand(1021);

    // ------------------------------------------------------------------------
    // Variables --------------------------------------------------------------
    // ------------------------------------------------------------------------

    /**
     * The list of breakpoints in the UI.
     */
    private TList breakpointList;

    /**
     * The list of breakpoints in the project.
     */
    private List<Breakpoint> breakpoints;

    // ------------------------------------------------------------------------
    // Constructors -----------------------------------------------------------
    // ------------------------------------------------------------------------

    /**
     * Construct window.
     *
     * @param parent the main application
     */
    public BreakpointsWindow(final TranquilApplication parent) {
        super(parent, i18n.getString("windowTitle"), 0, 1, 76, 15,
            MODAL | CENTERED);

        statusBar = newStatusBar(i18n.getString("statusBar"));
        statusBar.addShortcutKeypress(kbF1, cmHelp,
            i18n.getString("statusBarHelp"));
        statusBar.addShortcutKeypress(kbEnter, cmEditBreakpoint,
            i18n.getString("statusBarEdit"));
        statusBar.addShortcutKeypress(kbDel, cmDeleteBreakpoint,
            i18n.getString("statusBarDelete"));

        // Breakpoints list
        addLabel(i18n.getString("breakpointList"), 2, 1,
            new TAction() {
                public void DO() {
                    BreakpointsWindow.this.activate(breakpointList);
                }
            });
        breakpointList = addList(new ArrayList<String>(), 2, 2,
            getWidth() - 5, 8);

        // Buttons
        addButton(i18n.getString("okButton"), 2, getHeight() - 4,
            new TAction() {
                public void DO() {
                    BreakpointsWindow.this.close();
                }
            });

        addButton(i18n.getString("editButton"), 13, getHeight() - 4,
            new TAction() {
                public void DO() {
                    editBreakpoint();
                }
            });

        addButton(i18n.getString("deleteButton"), 24, getHeight() - 4,
            new TAction() {
                public void DO() {
                    deleteBreakpoint();
                }
            });

        addButton(i18n.getString("viewButton"), 35, getHeight() - 4,
            new TAction() {
                public void DO() {
                    viewBreakpoint();
                }
            });

        TButton cancelButton = addButton(i18n.getString("cancelButton"),
            60, getHeight() - 4,
            new TAction() {
                public void DO() {
                    BreakpointsWindow.this.close();
                }
            });

        // Save this for last: make the cancel button default action.
        activate(cancelButton);

        loadProject(parent.getProject());
    }

    // ------------------------------------------------------------------------
    // Event handlers ---------------------------------------------------------
    // ------------------------------------------------------------------------

    /**
     * Handle posted command events.
     *
     * @param command command event
     */
    @Override
    public void onCommand(final TCommandEvent command) {
        if (command.equals(cmEditBreakpoint)) {
            editBreakpoint();
        } else if (command.equals(cmDeleteBreakpoint)) {
            deleteBreakpoint();
        } else {
            // I didn't take it, pass it on.
            super.onCommand(command);
        }
    }

    // ------------------------------------------------------------------------
    // TWindow ----------------------------------------------------------------
    // ------------------------------------------------------------------------

    // ------------------------------------------------------------------------
    // BreakpointsWindow ------------------------------------------------------
    // ------------------------------------------------------------------------

    /**
     * Load breakpoints from a project.
     *
     * @param project the project to load from
     */
    private void loadProject(final Project project) {
        if (project == null) {
            return;
        }
        breakpoints = new ArrayList<Breakpoint>();
        for (Target target: project.getTargets()) {
            if (target instanceof FileTarget) {
                breakpoints.addAll(((FileTarget) target).getBreakpoints());
            }
        }
        List<String> breakpointStrings = new ArrayList<String>();
        for (Breakpoint bp: breakpoints) {
            breakpointStrings.add(String.format("%-28s %5d %31d",
                    bp.getTarget().getName(), bp.getLine(), bp.getPassCount()));
        }
        breakpointList.setList(breakpointStrings);
    }

    /**
     * Delete the selected breakpoint.
     */
    private void deleteBreakpoint() {
        int idx = breakpointList.getSelectedIndex();
        if ((idx < 0) || (idx >= breakpoints.size())) {
            return;
        }

        // Remove breakpoint from project.
        Breakpoint bp = breakpoints.get(idx);
        bp.getTarget().removeBreakpoint(bp.getLine());
        TranquilApplication app = (TranquilApplication) getApplication();
        loadProject(app.getProject());

        // Remove breakpoint from running debugger and editor window.
        if (app.getDebugger() != null) {
            app.getDebugger().removeBreakpoint(bp.getTarget(), bp.getLine());
        }
        InternalEditorWindow editor = app.findInternalEditor(bp.getTarget());
        if (editor != null) {
            editor.removeBreakpoint(bp.getLine());
        }
    }

    /**
     * View the selected breakpoint.
     */
    private void viewBreakpoint() {
        int idx = breakpointList.getSelectedIndex();
        if ((idx < 0) || (idx >= breakpoints.size())) {
            return;
        }

        // Switch editor window to breakpoint location.
        Breakpoint bp = breakpoints.get(idx);
        TranquilApplication app = (TranquilApplication) getApplication();
        InternalEditorWindow editor = app.findInternalEditor(bp.getTarget());
        if (editor != null) {
            // We will switch to this breakpoint.  Close this window first,
            // so that we can raise the editor window.
            close();

            editor.activate();
            editor.setEditingRowNumber(bp.getLine());
        }
    }

    /**
     * Edit the selected breakpoint.
     */
    private void editBreakpoint() {
        int idx = breakpointList.getSelectedIndex();
        if ((idx < 0) || (idx >= breakpoints.size())) {
            return;
        }

        // TODO

    }

}
